#pragma once
#include <iostream>
#include <sys/epoll.h>
#include "Common.hpp"
#include "InetAddr.hpp"
#include "Log.hpp"
#include "Socket.hpp"

using namespace LogModule;

class EpollServer
{

	const static int size = sizeof(fd_set) * 8;
	const static int defaultfd = -1;

public:
	EpollServer(uint16_t port) : _epfd(defaultfd)
	{
		_listensock = std::make_unique<TcpSocket>();
		_listensock->BulidTcpSocketMethod(port);

		_isrunning = false;
		// 创建epoll实例
		_epfd = epoll_create(256);

		// 注册监听套接字
		struct epoll_event ev;
		ev.events = EPOLLIN; // 关心读事件
		ev.data.fd = _listensock->GetFd();
		int fd = epoll_ctl(_epfd, EPOLL_CTL_ADD, _listensock->GetFd(), &ev);
		if (fd < 0)
		{
			LOG(LogLevel::ERROR) << "epoll_ctl error";
			return;
		}
	}

	void Start()
	{
		_isrunning = true;
		while (_isrunning)
		{
			int wait_fd = epoll_wait(_epfd, _revs, size, -1);
			if (wait_fd > 0)
			{
				//LOG(LogLevel::INFO) << "epoll_wait success";
				Dispatch(wait_fd);
			}
			else if (wait_fd == 0)
			{
				LOG(LogLevel::INFO) << "epoll_wait timeout";
			}
			else
			{
				LOG(LogLevel::ERROR) << "epoll_wait error";
				return;
			}
		}
	}

	void Dispatch(int fd)
	{
		for (int i = 0; i < size; i++)
		{

			if (_revs[i].events == EPOLLIN)
			{
				if (_revs[i].data.fd == _listensock->GetFd())
				{
					// 监听套接字
					Accepter();
				}
				else
				{
					// 数据套接字
					Receiver(_revs[i].data.fd);
				}
			}
		}
	}

	void Accepter()
	{
		InetAddr client;
		int fd = _listensock->Accept(&client);
		if (fd < 0)
		{
			LOG(LogLevel::ERROR) << "accept error";
			return;
		}

		// 注册新客户端FD到epoll
		struct epoll_event new_ev;
		new_ev.events = EPOLLIN; // 关心读事件
		new_ev.data.fd = fd;
		int ret = epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &new_ev);
		if (ret < 0)
		{
			LOG(LogLevel::ERROR) << "epoll_ctl error";
		}
	}

	void Receiver(int fd)
	{
		char buffer[1024];
		int ret = recv(fd, buffer, sizeof(buffer) - 1, 0);
		if (ret > 0)
		{
			buffer[ret] = 0;
			std::cout << buffer << std::endl;
		}
		else if (ret == 0)
		{
			// 对端关闭
			LOG(LogLevel::INFO) << "client close";
			epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
			close(fd);
		}
		else
		{
			LOG(LogLevel::ERROR) << "recv error";
			epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
			close(fd);
		}
	}

	void Stop()
	{
		_isrunning = false;
	}

	
	~EpollServer() {}

private:
	std::unique_ptr<Socket> _listensock;
	bool _isrunning;
	int _epfd;
	struct epoll_event _revs[size];
};